#include "ResMgrPch.h"

#include "MeshSkinned.h"

#include "VertexType.h"
#include "RenderFacade.h"
#include "XmlUtil.h"
#include "StringParseUtil.h"
#include "RenderUtil.h"

MeshSkinned::MeshSkinned(void) : MeshBase()
,m_worldTransformArray( NULL )
,m_inverseTransformArray( NULL )
{
	m_meshType = STATIC_MESH;
}

MeshSkinned::~MeshSkinned(void)
{
}

BOOL MeshSkinned::LoadFromXml( const char* fileName )
{
	XmlDocument doc;
	if( doc.LoadFile( fileName ) )
	{
		XmlNode * meshNode = doc.GetChildNode( "mesh" );
		m_name = meshNode->GetAttribute( "name" );

		XmlNode * verticesNode = meshNode->GetChildNode("vertices");
		std::string vertexStr = verticesNode->GetAttribute("type");

		m_vertexType = RenderUtil::GetInstance()->GetVertexTypeByString(vertexStr);

		int vertexStride = atoi( verticesNode->GetAttribute("stride") );
		m_uVertexCount = atoi( verticesNode->GetAttribute("count") );

		m_pVertices = new float[m_uVertexCount * vertexStride];

		FormatedNumberList vertexNumberList( verticesNode->GetText(), m_vertexType.m_format );
		vertexNumberList.Copy( m_pVertices );

		CreateVB();

		//
		XmlNode * indicesNode = meshNode->GetChildNode("indices");
		
		m_uIndexCount = atoi( indicesNode->GetAttribute("count") );

		m_pIndices = new DWORD[m_uIndexCount];

		FormatedNumberList indexNumberList( indicesNode->GetText(), "u" );
		indexNumberList.Copy( m_pIndices );

		CreateIB();

		// skin info
		XmlNode * skinInfoNode = meshNode->GetChildNode("skin_info");
		FormatedNumberList skinInfoNumberList( skinInfoNode->GetText(), "f" );
		UINT numberCount = skinInfoNumberList.GetNumberCount();
		float * skinInfoList = new float[numberCount];
		skinInfoNumberList.Copy( skinInfoList );
		for( UINT cnt = 0; cnt < numberCount; )
		{
			SkinInfo skinInfo;

			UINT boneCount = (UINT)skinInfoList[cnt++];
			for( UINT bCnt = 0; bCnt < boneCount; bCnt++ )
			{
				SkinInfoValue skinInfoValue;
				skinInfoValue.m_index = (UINT)skinInfoList[cnt++];
				skinInfoValue.m_weight = skinInfoList[cnt++];

				skinInfo.push_back( skinInfoValue );
			}

			m_skinInfoArray.push_back( skinInfo );
		}

		//
		XmlNode * renderGroupListNode = meshNode->GetChildNode("render_group_list");
		int renderGroupNodeCount = renderGroupListNode->GetChildNodeCount("render_group");
		for( int cnt = 0; cnt < renderGroupNodeCount; cnt++ )
		{
			XmlNode * renderGroupNode = renderGroupListNode->GetChildNode("render_group", cnt);

			RenderGroup renderGroup;
			renderGroup.m_name = renderGroupNode->GetAttribute("name");
			renderGroup.m_materialName = renderGroupNode->GetAttribute("material_name");
			renderGroup.m_startIndex = atoi( renderGroupNode->GetAttribute("start_index") );
			renderGroup.m_indexCount = atoi( renderGroupNode->GetAttribute("index_count") );

			m_renderGroupList.push_back(renderGroup);
		}

		//
		XmlNode * materialListNode = meshNode->GetChildNode("material_list");
		int materialNodeCount = materialListNode->GetChildNodeCount("material");
		for( int cnt = 0; cnt < materialNodeCount; cnt++ )
		{
			XmlNode * materialNode = materialListNode->GetChildNode("material", cnt);
			Material * meterial = new Material();
			if( meterial->LoadFromXml( materialNode ) )
			{
				m_materialMap[meterial->GetName()] = meterial;
			}
			else
			{
				SAFE_DELETE( meterial );
			}
		}
	}

	return TRUE;
}

void MeshSkinned::Render()
{
	IndexedPrimitiveInfo indexedPrimitiveInfo;
	indexedPrimitiveInfo.m_pVB = m_pVB;
	indexedPrimitiveInfo.m_pIB = m_pIB;
	indexedPrimitiveInfo.m_fvf = m_vertexType.m_fvf;
	indexedPrimitiveInfo.m_stride = m_vertexType.m_size;
	indexedPrimitiveInfo.m_primitiveType = D3DPT_TRIANGLELIST;
	indexedPrimitiveInfo.m_baseVertexIndex = 0;
	indexedPrimitiveInfo.m_numVertices = m_uVertexCount; 
	indexedPrimitiveInfo.m_minIndex = 0;

	int renderGroupCount = (int)m_renderGroupList.size();
	for( int cnt = 0; cnt < renderGroupCount; cnt++ )
	{
		indexedPrimitiveInfo.m_startIndex = m_renderGroupList[cnt].m_startIndex; 
		indexedPrimitiveInfo.m_triangleCount = m_renderGroupList[cnt].m_indexCount / 3;

		Material * material = NULL;
		std::map<std::string, Material *>::iterator it = m_materialMap.find( m_renderGroupList[cnt].m_materialName );
		if( it != m_materialMap.end() )
		{
			material = it->second;
		}

		Val3DRendererUnit unit;
		unit.m_worldTransform = Matrix::IDENTITY;
		unit.m_material = material;
		unit.m_indexedPrimitiveInfo = indexedPrimitiveInfo;

		if( RenderFacade::GetInstance() )
		{
			RenderFacade::GetInstance()->Get3DRenderer()->RenderImmediately( unit );
		}
	}
}